package com.cloud.rou.im.client.statemachine;

import lombok.Setter;

import java.util.HashMap;
import java.util.Map;

/**
 * <p></p>
 *
 * @author GaoShuangWen
 */
public class StateMachine {

    private MsgState currentState;

    private Map<MsgState,StateAction> stateMap;

    @Setter
    private StateMachineContext context = new StateMachineContext();

    public StateMachine(MsgState currentState,Map<MsgState,StateAction> stateMap) {
        this.currentState=currentState;
        this.stateMap=stateMap;
    }

    public void fire(MsgEvent event) {
        if(event==MsgEvent.ERROR){
            System.out.println("发送失败");
        }
        StateAction stateAction = getStateAction(currentState);
        Transition transition = stateAction.getTransition(event);
        MsgState toState = transition.getToState();
        if (null == toState) {
            transition.action(context);
        } else {
            // 先调用之前的退出  -  再调用进入最新的状态

            stateAction.exit(context);
            StateAction toStateAction = getStateAction(toState);
            toStateAction.entry(context);
            transition.action(context);
            currentState = toState;
        }

    }

    public MsgState getState() {
        return currentState;
    }

    public StateMachineContext getContext() {
        return context;
    }



    private StateAction getStateAction(MsgState state) {
       return stateMap.get(state);
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        private MsgState currentState;

        private Map<MsgState, StateAction.Builder> maps = new HashMap<>();

        private Map<MsgState,StateAction> stateMap = new HashMap<>();

        public void initialState(MsgState state) {
            this.currentState = state;
        }

        public StateAction.Builder state(MsgState state) {
            StateAction.Builder builder = maps.get(state);
            if(builder!=null){
                return builder;
            }
            StateAction.Builder builder1 = StateAction.builder(state);
            maps.put(state,builder1);
            return builder1;
        }

        public StateMachine build() {
            maps.forEach((state, builder) -> {
                stateMap.put(state,builder.build());
            });
            return new StateMachine(currentState,this.stateMap);
        }
    }

    public static void main(String[] args) {

      /*  build.fire(MsgEvent.SEND);
        build.fire(MsgEvent.DELAY);
        build.fire(MsgEvent.RETRY_SEND);
        build.fire(MsgEvent.DELAY);
        build.fire(MsgEvent.RETRY_SEND);
        build.fire(MsgEvent.ACK);*/
    }

}